SPB Git forge

spb/ai-atlas

Public
41commits 1branches 0releases
4.6 MBsize
maindefault branch
12 days agolast push
HTML 77.2% TypeScript 10.5% Python 9.6% JavaScript 2.5%
16.2 KB · 276 lines tsx
Raw Blame History
1import { ExternalLink } from 'lucide-react';2import type { Metadata } from 'next';3import Link from 'next/link';4import { permanentRedirect } from 'next/navigation';5import { CompareButton } from '@/components/compare/compare-button';6import { CompareTrayBar } from '@/components/compare/compare-tray-bar';7import { RelationsBlock, SourcesTable, TimelineList } from '@/components/entity/blocks';8import { buildMetadata, loadEntity } from '@/components/entity/load';9import { Methodology } from '@/components/intelligence/bits';10import { ExpandableOfferRow } from '@/components/intelligence/expand-price-row';11import { ViewBeacon } from '@/components/layout/view-beacon';12import { PriceMovers } from '@/components/prices/movers';13import { ProviderStrip } from '@/components/providers/provider-strip';14import { Chip, EntityBadge, StatusBadge } from '@/components/ui/badges';15import { DataTable, EmptyRow, Td, Th } from '@/components/ui/data-table';16import { EntityLink, QualityMark } from '@/components/ui/entity';17import { KeyValue } from '@/components/ui/key-value';18import { SourceCell } from '@/components/ui/provenance';19import { Container, Note, Section } from '@/components/ui/section';20import { EmptyState, Unavailable } from '@/components/ui/unavailable';21import { WatchButton } from '@/components/watchlist/watch-button';22import { api, intel, safe } from '@/lib/api';23import { fmtAgo, fmtDate, fmtInt, fmtTokens, fmtUsdPerM, num } from '@/lib/format';24import { PROSE_KEYS, routes, SITE_NAME, SITE_URL } from '@/lib/site';25import type { Deployment } from '@/lib/types';2627export const revalidate = 300;28type Params = { params: Promise<{ slug: string }> };29const FEATURE_LABELS: Record<string, string> = { batch: 'Batch', cached: 'Prompt caching', fine_tuning: 'Fine-tuning', audio: 'Audio', image: 'Image', video: 'Video', web_search: 'Web search', flex: 'Flex tier', long_context: 'Long-context tier', priority: 'Priority tier' };3031export async function generateMetadata({ params }: Params): Promise<Metadata> {32  const { slug } = await params;33  const d = await safe(api.entityOfType('providers', slug));34  if (!d || d.entity_type !== 'provider') return { title: 'Provider', robots: { index: false } };35  const m = buildMetadata(d);36  return { ...m, title: `${d.name} — models served, prices per 1M tokens, price history`, description: `${d.name}${d.organization ? ` (${d.organization.name})` : ''}: every model it currently serves with published input, output, cached and batch prices per 1M tokens, context windows, price distributions, listings, delistings and price change events — each with its source. ${SITE_NAME}.` };37}3839export default async function ProviderPage({ params }: Params) {40  const { slug } = await params;41  const d = await loadEntity('providers', slug);42  const canonical = routes.entity(d);43  if (canonical !== `/providers/${encodeURIComponent(slug)}`) permanentRedirect(canonical);44  const since = Date.now() - 30 * 86400000;45  const [providers, current, closed, priceEvents] = await Promise.all([safe(intel.providers()), safe(intel.deployments({ provider: d.slug, limit: 200, sort: 'model' })), safe(intel.deployments({ provider: d.slug, current: 0, limit: 200, sort: 'valid_from' })), safe(api.changes({ type: 'PRICE_CHANGED', limit: 200 }))]);46  const row = providers?.items.find((p) => p.slug === d.slug) ?? null;47  const deployments: Deployment[] = current?.items ?? [];48  const added = deployments.filter((x) => new Date(x.valid_from).getTime() >= since).sort((a, b) => b.valid_from.localeCompare(a.valid_from));49  const removed = (closed?.items ?? []).filter((x) => x.status === 'delisted' || x.valid_to).sort((a, b) => (b.valid_to ?? '').localeCompare(a.valid_to ?? ''));50  const events = (priceEvents?.items ?? []).filter((e) => e.meta?.provider_id === d.id || e.meta?.provider === d.name);51  const orgs = [...new Map(deployments.filter((x) => x.model.organization).map((x) => [x.model.organization!.slug, x.model.organization!])).values()].sort((a, b) => a.name.localeCompare(b.name));52  const featureKeys = row?.feature_keys ?? [...new Set(deployments.flatMap((x) => Object.keys(x.features ?? {}).concat(Object.keys(x.prices.native_units ?? {}))))].sort();53  const a = d.attributes ?? {};54  const specRows = Object.keys(a)55    .filter((k) => !PROSE_KEYS.has(k))56    .map((k) => ({ key: k, raw: a[k] }));57  const ld = {58    '@context': 'https://schema.org',59    '@type': 'Organization',60    name: d.name,61    url: typeof a.website === 'string' ? a.website : undefined,62    description: d.description ?? undefined,63    parentOrganization: d.organization ? { '@type': 'Organization', name: d.organization.name } : undefined,64    mainEntityOfPage: `${SITE_URL}${canonical}`,65  };6667  return (68    <Container wide>69      <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(ld) }} />70      <ViewBeacon path={canonical} />71      <header className="pb-5 pt-7 md:pt-10">72        <div className="flex flex-wrap items-center gap-2 text-sm text-ink-3">73          <Link href={routes.providers()} className="hover:text-ink">Providers</Link> <span aria-hidden>/</span>74          <EntityBadge type={d.entity_type} />75          <StatusBadge status={d.status} />76        </div>77        <div className="mt-2 flex flex-col gap-4 md:flex-row md:items-end md:justify-between">78          <div className="min-w-0">79            <h1 className="display text-[28px] md:text-[40px]">{d.name}</h1>80            <p className="mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-sm text-ink-2">81              {d.organization && (82                <Link href={routes.entity({ entity_type: 'company', slug: d.organization.slug })} className="hover:text-accent">83                  Operated by {d.organization.name}84                </Link>85              )}86              {typeof a.website === 'string' && (87                <a href={a.website} target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-1 hover:text-accent">88                  {a.website.replace(/^https?:\/\/(www\.)?/, '').replace(/\/$/, '')} <ExternalLink className="size-3" aria-hidden />89                </a>90              )}91              {typeof a.pricing_url === 'string' && (92                <a href={a.pricing_url} target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-1 hover:text-accent">93                  pricing page <ExternalLink className="size-3" aria-hidden />94                </a>95              )}96              <QualityMark q={d.quality?.score} label />97            </p>98            {d.description && <p className="mt-3 max-w-2xl text-[15px] leading-relaxed text-ink-2">{d.description}</p>}99          </div>100          <div className="flex shrink-0 flex-wrap items-center gap-2">101            <CompareButton e={d} />102            <WatchButton e={d} />103            <Link href={routes.graph(d.slug)} className="inline-flex h-9 items-center border border-rule px-2.5 text-sm text-ink-2 hover:border-rule-strong hover:text-ink">104              Explore graph105            </Link>106          </div>107        </div>108      </header>109110      {row ? <ProviderStrip p={row} note={providers?.note} /> : <Unavailable what="Provider aggregates" compact />}111112      {/* ---------------------------------------------------------------------------------------- models served */}113      <Section eyebrow="Models served" title={`${fmtInt(current?.total ?? deployments.length)} current deployments`} lede="One row per model × provider model id, as published. Expand a row to load its full price history as a step chart." action={{ href: `${routes.prices()}?provider=${encodeURIComponent(d.slug)}`, label: 'In the price terminal' }} hairline={false}>114        {!current ? (115          <Unavailable what="Deployments" />116        ) : deployments.length === 0 ? (117          <EmptyState title="No current deployment recorded">The pricing page has not yielded a priced model row yet.</EmptyState>118        ) : (119          <DataTable scroll compact>120            <thead>121              <tr>122                <Th>Model</Th>123                <Th>Provider model id</Th>124                <Th num>Context</Th>125                <Th num>Input / 1M</Th>126                <Th num>Output / 1M</Th>127                <Th num>Cached in</Th>128                <Th num>Batch in / out</Th>129                <Th>Status</Th>130                <Th>Observed</Th>131                <Th>Source</Th>132                <Th className="w-24" aria-label="History" />133              </tr>134            </thead>135            <tbody>136              {deployments.map((x) => (137                <ExpandableOfferRow key={x.id} model={x.model.slug} provider={d.slug} colSpan={10} mode="step">138                  <Td primary>139                    <EntityLink e={x.model} />140                    {x.model.organization && <span className="ml-2 text-xs text-ink-3">{x.model.organization.name}</span>}141                  </Td>142                  <Td label="Provider model id" className="mono text-[11px] text-ink-2">{x.provider_model_id ?? '—'}</Td>143                  <Td num label="Context" className="tnum text-ink-2">{fmtTokens(x.context_length)}</Td>144                  <Td num label="Input / 1M" className="tnum text-accent-2">{fmtUsdPerM(x.prices.input)}</Td>145                  <Td num label="Output / 1M" className="tnum text-accent-2">{fmtUsdPerM(x.prices.output)}</Td>146                  <Td num label="Cached in" className="tnum text-ink-2">{fmtUsdPerM(x.prices.cached_input)}</Td>147                  <Td num label="Batch" className="tnum text-ink-2">{num(x.prices.batch_input) === null && num(x.prices.batch_output) === null ? <span className="text-ink-3">—</span> : `${fmtUsdPerM(x.prices.batch_input)} / ${fmtUsdPerM(x.prices.batch_output)}`}</Td>148                  <Td label="Status"><StatusBadge status={x.status} /></Td>149                  <Td label="Observed" className="text-ink-2 whitespace-nowrap" title={x.observed_at}>{fmtAgo(x.observed_at)}</Td>150                  <Td label="Source"><SourceCell url={x.source_url} tier={x.tier} /></Td>151                </ExpandableOfferRow>152              ))}153              {deployments.length === 0 && <EmptyRow cols={11} />}154            </tbody>155          </DataTable>156        )}157        {current && current.total > deployments.length && <Note className="mt-2">Showing the first {fmtInt(deployments.length)} of {fmtInt(current.total)} deployments — the rest are in the <Link href={`${routes.prices()}?provider=${encodeURIComponent(d.slug)}`} className="link">price terminal</Link>.</Note>}158      </Section>159160      {/* ----------------------------------------------------------------------------------- added / removed */}161      <Section eyebrow="Listings · 30 days" title="Models added and removed">162        <div className="grid grid-cols-[minmax(0,1fr)] gap-8 md:grid-cols-2">163          <div>164            <p className="flex items-baseline justify-between text-sm">165              <span className="font-medium text-ink">Added</span>166              <span className="tnum text-ink-3">{fmtInt(row?.models_added_30d ?? added.length)}</span>167            </p>168            {added.length ? (169              <ul className="mt-2 border-t border-rule">170                {added.slice(0, 12).map((x) => (171                  <li key={x.id} className="flex flex-wrap items-baseline gap-x-3 border-b border-rule py-2 text-sm">172                    <EntityLink e={x.model} />173                    <span className="tnum ml-auto text-xs text-ink-3">{fmtDate(x.valid_from)}</span>174                  </li>175                ))}176                {added.length > 12 && <li className="py-2 text-xs text-ink-3">+{added.length - 12} more in the table above.</li>}177              </ul>178            ) : (179              <p className="mt-2 text-sm text-ink-3">No listing opened in the last 30 days.</p>180            )}181          </div>182          <div>183            <p className="flex items-baseline justify-between text-sm">184              <span className="font-medium text-ink">Removed</span>185              <span className="tnum text-ink-3">{fmtInt(row?.models_removed_30d ?? removed.length)}</span>186            </p>187            {removed.length ? (188              <ul className="mt-2 border-t border-rule">189                {removed.slice(0, 12).map((x) => (190                  <li key={x.id} className="flex flex-wrap items-baseline gap-x-3 border-b border-rule py-2 text-sm">191                    <EntityLink e={x.model} />192                    <Chip>{x.status}</Chip>193                    <span className="tnum ml-auto text-xs text-ink-3">{fmtDate(x.valid_to)}</span>194                  </li>195                ))}196              </ul>197            ) : (198              <p className="mt-2 text-sm text-ink-3">No delisting recorded — a model that disappears from the pricing page is closed (valid_to) and listed here.</p>199            )}200          </div>201        </div>202      </Section>203204      {/* ------------------------------------------------------------------------------------- price events */}205      <Section eyebrow="Price events" title={`Price changes · ${fmtInt(row?.price_changes_30d ?? events.length)} in 30 days`} lede="PRICE_CHANGED events where this provider is the source of the price." action={{ href: `${routes.changes()}?type=PRICE_CHANGED`, label: 'All price events' }}>206        {!priceEvents ? <Unavailable what="Price events" /> : <PriceMovers movers={events} limit={50} />}207      </Section>208209      {/* ---------------------------------------------------------------------------------- features & limits */}210      <Section eyebrow="Features & limits" title="What this provider prices and publishes">211        <div className="grid grid-cols-[minmax(0,1fr)] gap-8 lg:grid-cols-[minmax(0,1fr)_minmax(0,1.2fr)]">212          <div>213            <p className="eyebrow mb-1.5">Priced features</p>214            {row?.features_supported?.length ? (215              <ul className="flex flex-wrap gap-1.5">216                {row.features_supported.map((f) => (217                  <li key={f}>218                    <Chip tone="accent">{FEATURE_LABELS[f] ?? f.replace(/_/g, ' ')}</Chip>219                  </li>220                ))}221              </ul>222            ) : (223              <p className="text-sm text-ink-3">No priced feature beyond input/output tokens recorded.</p>224            )}225            {featureKeys.length > 0 && (226              <>227                <p className="eyebrow mb-1.5 mt-4">Native price keys observed</p>228                <ul className="mono flex flex-wrap gap-1 text-[11px] text-ink-2">229                  {featureKeys.map((k) => (230                    <li key={k} className="rounded-[3px] bg-surface-2 px-1.5 py-[1px]">231                      {k}232                    </li>233                  ))}234                </ul>235                <Note className="mt-1.5">Provider-specific units (per 1K requests, per minute, per image…) are kept verbatim in each offer&apos;s native_units and are not converted.</Note>236              </>237            )}238            <p className="eyebrow mb-1.5 mt-4">Organizations covered</p>239            {orgs.length ? (240              <ul className="flex flex-wrap gap-1.5">241                {orgs.map((o) => (242                  <li key={o.slug}>243                    <Link href={routes.entity({ entity_type: 'company', slug: o.slug })} className="inline-flex h-7 items-center border border-rule px-2 text-xs text-ink-2 hover:border-rule-strong hover:text-ink">244                      {o.name}245                    </Link>246                  </li>247                ))}248              </ul>249            ) : (250              <p className="text-sm text-ink-3">—</p>251            )}252          </div>253          <div>254            <p className="eyebrow mb-1.5">Published attributes</p>255            <KeyValue rows={specRows} provenance={d.provenance} slug={d.slug} entity={{ name: d.name, entity_type: d.entity_type }} dense />256          </div>257        </div>258        <Methodology text={providers?.note} />259      </Section>260261      {d.relations?.length ? (262        <Section eyebrow="Relations" title="In the graph" action={{ href: routes.graph(d.slug), label: 'Explore graph' }}>263          <RelationsBlock relations={d.relations} exclude={['available_through']} />264        </Section>265      ) : null}266      <Section eyebrow="Timeline" title="Events" action={{ href: routes.timeline({ entity: d.slug }), label: 'Full timeline' }}>267        <TimelineList events={d.timeline ?? []} slug={d.slug} />268      </Section>269      <Section eyebrow="Sources" title="Where these facts come from">270        <SourcesTable sources={d.sources ?? []} />271      </Section>272      <CompareTrayBar />273    </Container>274  );275}276